package com.whfc.emp.manager.impl;

import com.whfc.common.enums.NetState;
import com.whfc.common.enums.*;
import com.whfc.common.exception.BizException;
import com.whfc.common.file.FileHandler;
import com.whfc.common.file.FilePathConfig;
import com.whfc.common.result.ResultEnum;
import com.whfc.common.util.*;
import com.whfc.emp.constant.RealNamePlatformConstant;
import com.whfc.emp.dao.*;
import com.whfc.emp.dto.AppFaceGateDTO;
import com.whfc.emp.dto.AppGroupDTO;
import com.whfc.emp.entity.*;
import com.whfc.emp.enums.*;
import com.whfc.emp.manager.AppFaceGateManager;
import com.whfc.emp.manager.CommonEmpConfigManager;
import com.whfc.emp.param.EmpAttendSyncDataParam;
import com.whfc.emp.param.EmpDeviceSyncDataParam;
import com.whfc.emp.param.EmpGroupSyncDataParam;
import com.whfc.emp.param.EmpInfoSyncDataParam;
import com.whfc.emp.realNamePlatform.jingZhou.JINGZHOUApi;
import com.whfc.emp.redis.FaceGateRedisDao;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.ByteArrayInputStream;
import java.util.Date;
import java.util.List;
import java.util.concurrent.CompletableFuture;

/**
 * 闸机管理
 *
 * @author hw
 * @version 1.0
 * @date 2021/1/7 14:09
 */
@Service
public class AppFaceGateManagerImpl implements AppFaceGateManager {

    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    @Autowired
    private AppEmpMapper appEmpMapper;

    @Autowired
    private AppEmpDataMapper empDataMapper;

    @Autowired
    private AppEmpDayMapper appEmpDayMapper;

    @Autowired
    private AppEmpGroupMapper appEmpGroupMapper;

    @Autowired
    private AppFaceGateMapper appFaceGateMapper;

    @Autowired
    private CommonEmpConfigManager commonEmpConfigManager;

    @Autowired
    private AppEmpAttendRecordMapper appEmpAttendRecordMapper;

    @Autowired
    private AppFaceGateRecordMapper appFaceGateRecordMapper;

    @Autowired
    private AppEmpWorkTypeMapper appEmpWorkTypeMapper;

    @Autowired
    private FaceGateRedisDao faceGateRedisDao;

    /**
     * 默认工人类型 建筑工人
     */
    private static final Integer DEFAULT_WORK_ROLE_ID = 2;
    private static final String DEFAULT_WORK_ROLE_NAME = "建筑工人";

    @Autowired
    private FilePathConfig filePathConfig;

    @Autowired
    private FileHandler fileHandler;

    @Autowired
    private AppSyncRealNameConfigDao appSyncRealNameConfigDao;

    @Override
    public void handleRec(EmpAttendSyncDataParam dataParam) throws BizException {
        logger.info("考勤记录同步,dataParam:{}", dataParam);
        if (dataParam == null) {
            return;
        }
        Integer deptId = dataParam.getDeptId();
        String personGuid = dataParam.getPersonGuid();
        String deviceKey = dataParam.getDeviceKey();
        Date showTime = dataParam.getShowTime();
        Integer direction = dataParam.getDirection();
        String idCardNo = dataParam.getIdCardNo();
        Integer empId = dataParam.getEmpId();
        // (3) 验证人员-唯一标识
        AppEmp emp = null;
        if (StringUtils.isNotBlank(idCardNo)) {
            emp = appEmpMapper.selectByDeptIdAndIdCardNo(deptId, idCardNo);
        } else if (empId != null) {
            emp = appEmpMapper.selectByPrimaryKey(empId);
        } else if (StringUtils.isNotBlank(personGuid)) {
            emp = appEmpMapper.selectByDeptIdAndEmpCode(deptId, personGuid);
        }

        String empName = dataParam.getEmpName();
        Integer type = FaceRecType.VISITOR.getValue();
        if (emp == null) {
            logger.warn("考勤记录同步, 未找到人员, deptId:{}, personGuid:{}, name:{}", deptId, personGuid, dataParam.getEmpName());
        } else {
            empId = emp.getId();
            empName = emp.getEmpName();
            type = FaceRecType.EMPLOYEE.getValue();
        }
        // (4) 保存识别记录
        AppFaceGateRecord appFaceGateRecord = new AppFaceGateRecord();
        appFaceGateRecord.setFaceGateId(dataParam.getFaceGateId());
        appFaceGateRecord.setDeviceKey(deviceKey);
        appFaceGateRecord.setPersonGuid(personGuid);
        appFaceGateRecord.setEmpId(empId);
        appFaceGateRecord.setEmpName(empName);
        appFaceGateRecord.setTemperature(dataParam.getTemperature());
        appFaceGateRecord.setData(dataParam.getData());
        String picture = dataParam.getPicture();
        appFaceGateRecord.setPhotoUrl(picture);

        appFaceGateRecord.setShowTime(showTime);
        appFaceGateRecord.setRecMode(dataParam.getRecMode());
        appFaceGateRecord.setType(type);
        appFaceGateRecord.setDeptId(deptId);
        appFaceGateRecordMapper.insertSelective(appFaceGateRecord);
        // 人员不存在或者已离职不做后续操作
        if (emp == null || PostState.OUTER.getValue().equals(emp.getPostState())) {
            return;
        }
        // (5) 计算出勤状态,更新出勤记录
        attendStateHandle(deptId, showTime, direction, empId, empName, picture);
    }


    @Override
    public void handleEmpInfo(EmpInfoSyncDataParam dataParam) throws BizException {
        logger.info("闸机人员信息同步,dataParam:{}", dataParam);
        if (dataParam == null) {
            return;
        }
        String syncType = dataParam.getSyncType();
        if (FaceGateSyncOp.EMP_ADD_OR_UPDATE.getValue().equals(syncType)) {
            //新增或者更新
            addEmp(dataParam);
        } else if (FaceGateSyncOp.EMP_DEL.getValue().equals(syncType)) {
            //删除人员
            delEmp(dataParam);
        }
    }


    @Override
    public void handleGroup(EmpGroupSyncDataParam dataParam) throws BizException {
        logger.info("班组信息同步：dataParam：{}", dataParam);
        if (dataParam == null) {
            return;
        }
        Integer deptId = dataParam.getDeptId();
        String groupCode = dataParam.getGroupCode();
        AppEmpGroup record = new AppEmpGroup();
        record.setCorpId(0);
        record.setCorpName("默认合作单位");
        record.setDeptId(deptId);
        record.setGroupCode(groupCode);
        record.setGroupName(dataParam.getGroupName());
        AppEmpGroup appEmpGroup = appEmpGroupMapper.selectGroupCodeAndDeptId(groupCode, deptId);
        if (appEmpGroup == null) {
            appEmpGroupMapper.insertSelective(record);
            return;
        }
        record.setId(appEmpGroup.getId());
        appEmpGroupMapper.updateByPrimaryKeySelective(record);
    }


    @Override
    public void handleDevice(EmpDeviceSyncDataParam dataParam) throws BizException {
        logger.info("闸机设备信息同步,dataParam:{}", dataParam);
        if (dataParam == null) {
            return;
        }
        String syncType = dataParam.getSyncType();
        if (FaceGateSyncOp.DEVICE_ADD_OR_UPDATE.getValue().equals(syncType)) {
            //新增或者更新
            addDevice(dataParam);
        } else if (FaceGateSyncOp.DEVICE_DEL.getValue().equals(syncType)) {
            //删除人员
            delDevice(dataParam);
        }
    }

    @Override
    public AppFaceGateDTO getByDeviceKey(String deviceKey) throws BizException {
        if (StringUtils.isBlank(deviceKey)) {
            return null;
        }
        //从缓存中获取闸机信息
        AppFaceGateDTO faceGateDTO = faceGateRedisDao.get(deviceKey);
        if (faceGateDTO != null) {
            return faceGateDTO;
        }
        //从数据库中获取闸机信息
        AppFaceGate appFaceGate = appFaceGateMapper.selectByDeviceKey(deviceKey);
        if (appFaceGate == null) {
            return null;
        }
        AppFaceGateDTO appFaceGateDTO = new AppFaceGateDTO();
        BeanUtils.copyProperties(appFaceGate, appFaceGateDTO);
        appFaceGateDTO.setFaceGateId(appFaceGate.getId());
        //保存闸机信息到缓存中
        faceGateRedisDao.set(deviceKey, appFaceGateDTO);
        return appFaceGateDTO;
    }

    /**
     * 新增或者修改人员
     *
     * @param dataParam 人员信息
     */
    private void addEmp(EmpInfoSyncDataParam dataParam) {
        logger.info("新增人员信息, params:{}", dataParam);
        Integer deptId = dataParam.getDeptId();
        if (deptId == null) {
            throw new BizException(ResultEnum.PARAM_ERROR.getCode(), "组织机构ID为空，无法新增人员");
        }
        String empCode = dataParam.getEmpCode();
        String idCardNo = dataParam.getIdCardNo();
        //查找人员信息 存在则更新 不存在则新增
        AppEmp appEmp = null;
        if (StringUtils.isNotBlank(idCardNo)) {
            appEmp = appEmpMapper.selectByDeptIdAndIdCardNo(deptId, idCardNo);
        } else if (StringUtils.isNotBlank(empCode)) {
            appEmp = appEmpMapper.selectByDeptIdAndEmpCode(deptId, empCode);
        }

        if (appEmp == null) {
            appEmp = new AppEmp();
        }
        //设置人员头像
        setEmpImg(dataParam);

        appEmp.setProjectId(deptId);
        appEmp.setDeptId(deptId);
        appEmp.setEmpName(dataParam.getEmpName());
        appEmp.setEmpCode(dataParam.getEmpCode());
        appEmp.setGender(dataParam.getGender());
        appEmp.setPhone(dataParam.getPhone());
        appEmp.setIdCardNo(dataParam.getIdCardNo());
        appEmp.setAddress(dataParam.getAddress());
        appEmp.setNation(dataParam.getNation());
        appEmp.setAvatar(dataParam.getAvatar());
        appEmp.setHeadImg(dataParam.getHeadImg());

        //班组处理
        String groupCode = dataParam.getGroupCode();
        if (StringUtils.isNotEmpty(groupCode)) {
            AppEmpGroup appEmpGroup = appEmpGroupMapper.selectGroupCodeAndDeptId(groupCode, deptId);
            if (appEmpGroup != null) {
                appEmp.setGroupId(appEmpGroup.getId());
                appEmp.setGroupName(appEmpGroup.getGroupName());
            }
        } else {
            //默认班组 取当前组织机构的第一个班组
            List<AppGroupDTO> list = appEmpGroupMapper.selectByDeptId(deptId, null);
            if (list != null && list.size() > 0) {
                AppGroupDTO groupDTO = list.get(0);
                appEmp.setCorpId(groupDTO.getCorpId());
                appEmp.setCorpName(groupDTO.getCorpName());
                appEmp.setGroupId(groupDTO.getGroupId());
                appEmp.setGroupName(groupDTO.getGroupName());
            }
        }

        //工种处理
        //查询传递过来的工种 没有则默认为 其他
        String workTypeName = StringUtils.isBlank(dataParam.getWorkTypeName()) ? "其他" : dataParam.getWorkTypeName();
        AppEmpWorkType appEmpWorkType = appEmpWorkTypeMapper.selectByDeptIdAndName(deptId, workTypeName);
        if (appEmpWorkType == null) {
            appEmpWorkType = new AppEmpWorkType();
            appEmpWorkType.setDeptId(deptId);
            appEmpWorkType.setName(workTypeName);
            appEmpWorkTypeMapper.insertSelective(appEmpWorkType);
        }
        appEmp.setWorkTypeId(appEmpWorkType.getId());
        appEmp.setWorkTypeName(appEmpWorkType.getName());

        //设置工人类型
        appEmp.setWorkRoleId(DEFAULT_WORK_ROLE_ID);
        appEmp.setWorkRoleName(DEFAULT_WORK_ROLE_NAME);

        //姓名拼音
        String empName = appEmp.getEmpName();
        if (StringUtils.isNotBlank(empName)) {
            appEmp.setEname(PinyinUtil.toPinyin(empName));
        }
        //删除标记
        appEmp.setDelFlag(DelFlag.UNDELETE.getValue());

        //保存人员信息
        if (appEmp.getId() == null) {
            //新增
            Date enterTime = dataParam.getEnterTime();
            if (enterTime == null) {
                enterTime = new Date();
            }
            appEmp.setEnterTime(enterTime);
            appEmpMapper.insertSelective(appEmp);
            //初始化 app_emp_data
            AppEmpData appEmpData = new AppEmpData();
            appEmpData.setEmpId(appEmp.getId());
            appEmpData.setNetState(NetState.OFFLINE.getValue());
            empDataMapper.insertOrUpdate(appEmpData);
        } else {
            //更新
            appEmpMapper.updateByPrimaryKeySelective(appEmp);
        }
    }


    /**
     * 删除人员
     *
     * @param dataParam 人员信息
     */
    private void delEmp(EmpInfoSyncDataParam dataParam) {
        logger.info("删除人员信息, params:{}", dataParam);
        //删除人员
        if (dataParam == null) {
            return;
        }
        Integer deptId = dataParam.getDeptId();
        String empCode = dataParam.getEmpCode();
        String idCardNo = dataParam.getIdCardNo();
        if (deptId == null) {
            return;
        }

        if (StringUtils.isNotBlank(idCardNo)) {
            appEmpMapper.delLogicByDeptIdAndIdCardNo(deptId, idCardNo);
        } else if (StringUtils.isNotBlank(empCode)) {
            appEmpMapper.delLogicByDeptIdAndEmpCode(deptId, empCode);
        }
    }


    /**
     * 新增设备
     *
     * @param dataParam 设备信息
     */
    private void addDevice(EmpDeviceSyncDataParam dataParam) {
        logger.info("新增闸机设备, params:{}", dataParam);
        if (dataParam == null) {
            return;
        }
        Integer deptId = dataParam.getDeptId();
        String deviceKey = dataParam.getDeviceKey();

        AppFaceGate faceGate = new AppFaceGate();
        faceGate.setDeptId(dataParam.getDeptId());
        faceGate.setName(dataParam.getDeviceName());
        faceGate.setDirection(dataParam.getDirection());
        faceGate.setDeviceKey(dataParam.getDeviceKey());
        faceGate.setPlatform(dataParam.getPlatform());

        AppFaceGateDTO appFaceGate = appFaceGateMapper.selectByDeptIdAndDeviceKey(deptId, deviceKey);

        if (appFaceGate == null) {
            //新增闸机
            appFaceGateMapper.insertSelective(faceGate);
        } else {
            //修改闸机
            faceGate.setId(appFaceGate.getFaceGateId());
            appFaceGateMapper.updateByPrimaryKeySelective(faceGate);
        }

    }


    /**
     * 删除设备
     *
     * @param dataParam 设备信息
     */
    private void delDevice(EmpDeviceSyncDataParam dataParam) {
        logger.info("删除闸机设备, params:{}", dataParam);
        if (dataParam == null) {
            return;
        }
        Integer deptId = dataParam.getDeptId();
        String deviceKey = dataParam.getDeviceKey();
        if (deptId == null || StringUtils.isBlank(deviceKey)) {
            return;
        }
        appFaceGateMapper.logicDelByDeptIdAndDeviceKey(deptId, deviceKey);
    }


    /**
     * 处理考勤状态
     *
     * @param deptId    组织机构ID
     * @param showTime  打卡时间
     * @param direction 进出方向
     * @param empId     人员ID
     * @param empName   人员姓名
     * @param picture   人员照片
     */
    private void attendStateHandle(Integer deptId, Date showTime, Integer direction, Integer empId, String empName, String picture) {
        // 计算出勤状态,更新出勤记录
        Date date = DateUtil.getDate(showTime);
        AppEmpDay empDay = appEmpDayMapper.selectByEmpIdAndDate(empId, date);
        if (empDay == null) {
            // 初始化
            empDay = new AppEmpDay();
            empDay.setEmpId(empId);
            empDay.setDeptId(deptId);
            empDay.setDate(date);
            empDay.setAttendState(AttendState.ABSENCE.getValue());
            empDay.setWarnCnt(0);
            empDay.setDoffCnt(0);
            empDay.setFallCnt(0);
            empDay.setDropCnt(0);
            appEmpDayMapper.insertSelective(empDay);
        }
        // 1 查询考勤方式
        AttendType attendType = commonEmpConfigManager.getAttendTypeByEmpId(empId);
        if (attendType.equals(AttendType.FACEGATE)) {
            // 查询最新的打卡记录
            AppEmpAttendRecord appEmpAttendRecord = appEmpAttendRecordMapper
                    .selectLastAttendRecord(empId, AttendType.FACEGATE.getValue(), date);
            Date today = DateUtil.getDate(new Date());
            if (Direction.IN.getValue().equals(direction)) {
                //从闸机-进入
                // 更新人员最新状态
                if (today.equals(date)) {
                    appEmpDayMapper.updateAttendStateAndLocaleState(empId, AttendState.ATTEND.getValue(),
                            LocaleState.IN.getValue());
                }
                // 更新人员当天的状态
                appEmpDayMapper.updateAttend(empId, date, AttendType.FACEGATE.getValue());
                appEmpDayMapper.updateFaceGateStartTime(empId, date, showTime);
                if (appEmpAttendRecord != null && Direction.IN.getValue().equals(appEmpAttendRecord.getDirection())) {
                    // 更新考勤时间
                    int times = (int) ((showTime.getTime() - appEmpAttendRecord.getTime().getTime()) / 1000);
                    if (times > 0) {
                        appEmpDayMapper.updateFaceGateTimes(empId, date, times);
                    }
                }
            } else if (Direction.OUT.getValue().equals(direction)) {
                // 从闸机-出去
                // 更新人员最新状态
                if (today.equals(date)) {
                    appEmpDayMapper.updateLocaleState(empId, LocaleState.OUT.getValue());
                }
                appEmpDayMapper.updateFaceGateEndTime(empId, date, showTime);
                if (appEmpAttendRecord != null && Direction.IN.getValue().equals(appEmpAttendRecord.getDirection())) {
                    // 更新考勤时间
                    int times = (int) ((showTime.getTime() - appEmpAttendRecord.getTime().getTime()) / 1000);
                    if (times > 0) {
                        appEmpDayMapper.updateworkTimes(empId, date, times);
                    }
                }
            }
        }

        // 2 插入打卡记录
        AppEmpAttendRecord empAttendRecord = new AppEmpAttendRecord();
        empAttendRecord.setDeptId(deptId);
        empAttendRecord.setDirection(direction);
        empAttendRecord.setEmpId(empId);
//        empAttendRecord.setName(empName);
        empAttendRecord.setTime(showTime);
        empAttendRecord.setType(AttendType.FACEGATE.getValue());
        empAttendRecord.setPhoto(picture);
        appEmpAttendRecordMapper.insertSelective(empAttendRecord);

        // 同步考勤记录
        // 查询实名制配置
        CompletableFuture.runAsync(()->{
            AppSyncRealNameConfig appSyncRealNameConfig = appSyncRealNameConfigDao.selectByDeptIdAndPlatform(deptId, RealNamePlatformConstant.JING_ZHOU);
            if (appSyncRealNameConfig != null) {
                AppEmp appEmp = appEmpMapper.selectByPrimaryKey(empId);
                AppEmpGroup appEmpGroup = appEmpGroupMapper.selectByPrimaryKey(appEmp.getGroupId());
                logger.info("考勤同步荆州实名平台：empId={},empName={},groupCode={}",appEmp.getId(),appEmp.getEmpName(),appEmpGroup.getGroupCode());
                JINGZHOUApi.syncAtte(ImageUtil.base64EncodeAndCompress(picture,40),appEmp.getIdCardNo(),appEmpGroup.getGroupCode(),appSyncRealNameConfig,empAttendRecord);
            }
        });
    }


    /**
     * 设置人员头像
     *
     * @param dataParam 人员信息
     */
    private void setEmpImg(EmpInfoSyncDataParam dataParam) {
        //人员图片处理
        Integer imgType = dataParam.getImgType();
        String avatarImg = null;
        String headImg = null;
        String avatar = dataParam.getAvatar();
        String head = dataParam.getHeadImg();
        if (EmpSyncImgType.BASE64.getValue().equals(imgType)) {
            String avatarOssPath = "emp/avatar/img";
            String headOssPath = "emp/idcardhead/img";
            if (StringUtils.isNotBlank(avatar)) {
                avatarImg = uploadImg(avatar, avatarOssPath);
            }
            if (StringUtils.isNotBlank(head)) {
                headImg = uploadImg(head, headOssPath);
            }
        } else if (EmpSyncImgType.URL.getValue().equals(imgType)) {
            String http = "http";
            if (StringUtils.isNotBlank(avatar) && avatar.contains(http)) {
                avatarImg = avatar;
            }
            if (StringUtils.isNotBlank(head) && head.contains(http)) {
                headImg = head;
            }
        }
        dataParam.setAvatar(avatarImg);
        dataParam.setHeadImg(headImg);

    }


    /**
     * 上传识别照片
     *
     * @param base64Str base64
     * @return 图片地址
     */
    private String uploadImg(String base64Str, String ossPath) {
        String imgUrl = "";
        if (StringUtils.isEmpty(base64Str)) {
            return imgUrl;
        }
        try {
            byte[] imageByte = Base64Util.decode(base64Str);
            ByteArrayInputStream inputStream = new ByteArrayInputStream(imageByte);
            String path = filePathConfig.getFilePath(ossPath, RandomUtil.getRandomFileName(), "Jpeg");
            imgUrl = fileHandler.upload(path, inputStream);
        } catch (Exception e) {
            logger.warn("考勤识别上传base64图片失败", e);
        }
        return imgUrl;
    }

}
